#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include "led_operation.h"

static volatile unsigned int *CCM_CCGR1                              ;
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
static volatile unsigned int *GPIO5_GDIR                             ;
static volatile unsigned int *GPIO5_DR                               ;


static int board_imx_led_init(int which){ 
    printk(KERN_INFO "which is %d\n",which);
    if(which == 0){
        if (!CCM_CCGR1)
        {
            CCM_CCGR1                               = ioremap(0x20C406C, 4);
            IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4);
            GPIO5_GDIR                              = ioremap(0x020AC000 + 0x4, 4);
            GPIO5_DR                                = ioremap(0x020AC000 + 0, 4);
        }

        *CCM_CCGR1 |= (3<<30);

        unsigned int val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
        val &= ~(0xf);
        val |= (5);
        *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
        *GPIO5_GDIR |= (1<<3);
    }

    return 0;
}

static int board_imx_led_ctrl(int which, char status){
    if(which == 0){
        if (status == '0') {
            *GPIO5_DR &= ~(1<<3); // LED on
            printk(KERN_INFO "led 0 on"); 
        }
        else{
            *GPIO5_DR |= (1<<3);  // LED off
            printk(KERN_INFO "led 0 off");   
        } 
    }
    return 0;
}

static int board_imx_led_exit(void){
    if(!CCM_CCGR1){
        iounmap(GPIO5_DR);
        iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
        iounmap(GPIO5_GDIR);
        iounmap(CCM_CCGR1);
    }
}

static struct led_operation board_imx_led_optr = {
    .num  = 1,
    .init = board_imx_led_init,
    .ctrl = board_imx_led_ctrl,
    .exit = board_imx_led_exit,
};

struct led_operation *get_board_led_optr(void){
    return &board_imx_led_optr;
}